package utils

import (
	"bytes"
	"cashew.com/cashew_common/configs"
	"context"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/elastic/go-elasticsearch/v8"
	"github.com/elastic/go-elasticsearch/v8/esapi"
	"log"
	"strings"
)

var esClient *ESClient

type ESClient struct {
	Client *elasticsearch.Client
}

type ESSearchResponseData struct {
	Hits struct {
		Hits []struct {
			Source json.RawMessage `json:"_source"`
		} `json:"hits"`
	} `json:"hits"`
}

func GetEs() *ESClient {
	if esClient == nil {
		// 初始化ES客户端
		var err error
		esClient = new(ESClient)
		esClient.Client, err = newEsClient()
		if err != nil {
			log.Fatalf("Failed to initialize ES client: %v", err)
		}
	}

	return esClient
}

// 创建ES客户端
func newEsClient() (*elasticsearch.Client, error) {
	// 解析配置
	addresses := strings.Split(configs.EsAddr, ",")
	username := configs.EsUsername
	password := configs.EsPassword

	// 配置 Elasticsearch 客户端
	cfg := elasticsearch.Config{
		Addresses: addresses,
		Username:  username,
		Password:  password,
	}

	// 创建客户端
	client, err := elasticsearch.NewClient(cfg)
	if err != nil {
		fmt.Println("Failed to create ES client: %v", err)
		return nil, err
	}

	return client, nil
}

// 创建索引
func (es *ESClient) CreateIndex(index string, mapping string) error {
	req := esapi.IndicesCreateRequest{
		Index: index,
		Body:  strings.NewReader(mapping),
	}

	res, err := req.Do(context.Background(), es.Client)
	if err != nil {
		return fmt.Errorf("failed to create index: %w", err)
	}
	defer res.Body.Close()

	if res.IsError() {
		return fmt.Errorf("elasticsearch error: %s", res.String())
	}
	return nil
}

// 获取索引信息
func (es ESClient) GetIndex(index string) (map[string]interface{}, error) {
	req := esapi.IndicesGetRequest{
		Index: []string{index},
	}

	res, err := req.Do(context.Background(), es.Client)
	if err != nil {
		return nil, err
	}
	defer res.Body.Close()

	if res.IsError() {
		return nil, errors.New(res.String())
	}

	var result map[string]interface{}
	if err := json.NewDecoder(res.Body).Decode(&result); err != nil {
		return nil, err
	}

	return result, nil
}

// 检查索引是否存在
func (es ESClient) IndexExists(index string) (bool, error) {
	req := esapi.IndicesExistsRequest{
		Index: []string{index},
	}

	res, err := req.Do(context.Background(), es.Client)
	if err != nil {
		return false, err
	}
	defer res.Body.Close()

	return !res.IsError(), nil
}

// 更新索引设置
func (es ESClient) UpdateIndexSettings(index string, settings map[string]interface{}) error {
	body, err := json.Marshal(settings)
	if err != nil {
		return err
	}

	req := esapi.IndicesPutSettingsRequest{
		Index: []string{index},
		Body:  bytes.NewReader(body),
	}

	res, err := req.Do(context.Background(), es.Client)
	if err != nil {
		return err
	}
	defer res.Body.Close()

	if res.IsError() {
		return errors.New(res.String())
	}
	return nil
}

// 更新索引映射
func (es ESClient) UpdateIndexMapping(index string, mapping map[string]interface{}) error {
	body, err := json.Marshal(mapping)
	if err != nil {
		return err
	}

	req := esapi.IndicesPutMappingRequest{
		Index: []string{index},
		Body:  bytes.NewReader(body),
	}

	res, err := req.Do(context.Background(), es.Client)
	if err != nil {
		return err
	}
	defer res.Body.Close()

	if res.IsError() {
		return errors.New(res.String())
	}
	return nil
}

// 刷新索引
func (es ESClient) RefreshIndex(index string) error {
	req := esapi.IndicesRefreshRequest{
		Index: []string{index},
	}

	res, err := req.Do(context.Background(), es.Client)
	if err != nil {
		return err
	}
	defer res.Body.Close()

	if res.IsError() {
		return errors.New(res.String())
	}
	return nil
}

// 强制合并索引
func (es ESClient) ForceMergeIndex(index string) error {
	req := esapi.IndicesForcemergeRequest{
		Index: []string{index},
	}

	res, err := req.Do(context.Background(), es.Client)
	if err != nil {
		return err
	}
	defer res.Body.Close()

	if res.IsError() {
		return errors.New(res.String())
	}
	return nil
}

// 清除缓存
func (es ESClient) ClearCache(index string) error {
	req := esapi.IndicesClearCacheRequest{
		Index: []string{index},
	}

	res, err := req.Do(context.Background(), es.Client)
	if err != nil {
		return err
	}
	defer res.Body.Close()

	if res.IsError() {
		return errors.New(res.String())
	}
	return nil
}

// 获取索引统计信息
func (es ESClient) GetIndexStats(index string) (map[string]interface{}, error) {
	req := esapi.IndicesStatsRequest{
		Index: []string{index},
	}

	res, err := req.Do(context.Background(), es.Client)
	if err != nil {
		return nil, err
	}
	defer res.Body.Close()

	if res.IsError() {
		return nil, errors.New(res.String())
	}

	var result map[string]interface{}
	if err := json.NewDecoder(res.Body).Decode(&result); err != nil {
		return nil, err
	}

	return result, nil
}

// 获取索引别名
func (es ESClient) GetIndexAliases(index string) (map[string]interface{}, error) {
	req := esapi.IndicesGetAliasRequest{
		Index: []string{index},
	}

	res, err := req.Do(context.Background(), es.Client)
	if err != nil {
		return nil, err
	}
	defer res.Body.Close()

	if res.IsError() {
		return nil, errors.New(res.String())
	}

	var result map[string]interface{}
	if err := json.NewDecoder(res.Body).Decode(&result); err != nil {
		return nil, err
	}

	return result, nil
}

// 添加/更新索引别名
func (es ESClient) UpdateIndexAlias(index string, alias string) error {
	body := map[string]interface{}{
		"actions": []map[string]interface{}{
			{
				"add": map[string]interface{}{
					"index": index,
					"alias": alias,
				},
			},
		},
	}

	jsonBody, err := json.Marshal(body)
	if err != nil {
		return err
	}

	req := esapi.IndicesUpdateAliasesRequest{
		Body: bytes.NewReader(jsonBody),
	}

	res, err := req.Do(context.Background(), es.Client)
	if err != nil {
		return err
	}
	defer res.Body.Close()

	if res.IsError() {
		return errors.New(res.String())
	}
	return nil
}

// 删除索引别名
func (es ESClient) DeleteIndexAlias(index string, alias string) error {
	req := esapi.IndicesDeleteAliasRequest{
		Index: []string{index},
		Name:  []string{alias},
	}

	res, err := req.Do(context.Background(), es.Client)
	if err != nil {
		return err
	}
	defer res.Body.Close()

	if res.IsError() {
		return errors.New(res.String())
	}
	return nil
}

// 文档操作相关方法

// 获取文档
func (es ESClient) GetDocument(index, id string) (map[string]interface{}, error) {
	req := esapi.GetRequest{
		Index:      index,
		DocumentID: id,
	}

	res, err := req.Do(context.Background(), es.Client)
	if err != nil {
		return nil, err
	}
	defer res.Body.Close()

	if res.IsError() {
		if res.StatusCode == 404 {
			return nil, errors.New("document not found")
		}
		return nil, errors.New(res.String())
	}

	var result map[string]interface{}
	if err := json.NewDecoder(res.Body).Decode(&result); err != nil {
		return nil, err
	}

	return result, nil
}

// 创建文档
func (es ESClient) CreateDocument(index, id string, document interface{}) error {
	body, err := json.Marshal(document)
	if err != nil {
		return err
	}

	req := esapi.CreateRequest{
		Index:      index,
		DocumentID: id,
		Body:       bytes.NewReader(body),
	}

	res, err := req.Do(context.Background(), es.Client)
	if err != nil {
		return err
	}
	defer res.Body.Close()

	if res.IsError() {
		return errors.New(res.String())
	}
	return nil
}

// 更新文档
func (es ESClient) UpdateDocument(index, id string, document interface{}) error {
	body, err := json.Marshal(document)
	if err != nil {
		return err
	}

	req := esapi.UpdateRequest{
		Index:      index,
		DocumentID: id,
		Body:       bytes.NewReader(body),
	}

	res, err := req.Do(context.Background(), es.Client)
	if err != nil {
		return err
	}
	defer res.Body.Close()

	if res.IsError() {
		return errors.New(res.String())
	}
	return nil
}

// 删除文档
func (es ESClient) DeleteDocument(index, id string) error {
	req := esapi.DeleteRequest{
		Index:      index,
		DocumentID: id,
	}

	res, err := req.Do(context.Background(), es.Client)
	if err != nil {
		return err
	}
	defer res.Body.Close()

	if res.IsError() {
		return errors.New(res.String())
	}
	return nil
}

// 批量操作文档
func (es ESClient) BulkDocument(operations []map[string]interface{}) error {
	var buf bytes.Buffer
	for _, op := range operations {
		if err := json.NewEncoder(&buf).Encode(op); err != nil {
			return err
		}
	}

	req := esapi.BulkRequest{
		Body: &buf,
	}

	res, err := req.Do(context.Background(), es.Client)
	if err != nil {
		return err
	}
	defer res.Body.Close()

	if res.IsError() {
		return errors.New(res.String())
	}
	return nil
}

// 搜索文档
func (es ESClient) SearchDocuments(index string, query map[string]interface{}, from, size int) ([][]byte, error) {
	body, err := json.Marshal(query)
	if err != nil {
		return nil, err
	}

	req := esapi.SearchRequest{
		Index: []string{index},
		Body:  bytes.NewReader(body),
		From:  &from,
		Size:  &size,
	}

	res, err := req.Do(context.Background(), es.Client)
	if err != nil {
		return nil, err
	}
	defer res.Body.Close()

	if res.IsError() {
		return nil, errors.New(res.String())
	}

	var esResult ESSearchResponseData
	if err := json.NewDecoder(res.Body).Decode(&esResult); err != nil {
		return nil, err
	}

	result := [][]byte{}

	if len(esResult.Hits.Hits) == 0 {
		return result, nil
	}

	for _, hit := range esResult.Hits.Hits {
		result = append(result, hit.Source)
	}

	return result, nil
}

// 批量更新文档
func (es ESClient) BulkUpdateDocuments(index string, updates map[string]interface{}) error {
	var buf bytes.Buffer
	for id, doc := range updates {
		meta := map[string]interface{}{
			"update": map[string]interface{}{
				"_index": index,
				"_id":    id,
			},
		}
		if err := json.NewEncoder(&buf).Encode(meta); err != nil {
			return err
		}

		update := map[string]interface{}{
			"doc": doc,
		}
		if err := json.NewEncoder(&buf).Encode(update); err != nil {
			return err
		}
	}

	req := esapi.BulkRequest{
		Body: &buf,
	}

	res, err := req.Do(context.Background(), es.Client)
	if err != nil {
		return err
	}
	defer res.Body.Close()

	if res.IsError() {
		return errors.New(res.String())
	}
	return nil
}

// 批量删除文档
func (es ESClient) BulkDeleteDocuments(index string, ids []string) error {
	var buf bytes.Buffer
	for _, id := range ids {
		meta := map[string]interface{}{
			"delete": map[string]interface{}{
				"_index": index,
				"_id":    id,
			},
		}
		if err := json.NewEncoder(&buf).Encode(meta); err != nil {
			return err
		}
	}

	req := esapi.BulkRequest{
		Body: &buf,
	}

	res, err := req.Do(context.Background(), es.Client)
	if err != nil {
		return err
	}
	defer res.Body.Close()

	if res.IsError() {
		return errors.New(res.String())
	}
	return nil
}

// 获取文档数量
func (es ESClient) CountDocuments(index string, query map[string]interface{}) (int64, error) {
	body, err := json.Marshal(query)
	if err != nil {
		return 0, err
	}

	req := esapi.CountRequest{
		Index: []string{index},
		Body:  bytes.NewReader(body),
	}

	res, err := req.Do(context.Background(), es.Client)
	if err != nil {
		return 0, err
	}
	defer res.Body.Close()

	if res.IsError() {
		return 0, errors.New(res.String())
	}

	var result map[string]interface{}
	if err := json.NewDecoder(res.Body).Decode(&result); err != nil {
		return 0, err
	}

	return int64(result["count"].(float64)), nil
}
